#ifndef RTTRANSPORTTHREADPROXY_H
#define RTTRANSPORTTHREADPROXY_H

#include "RtConnectionInterface.h"
#include "RtThreadManager.h"
#include "RtInetAddr.h"
#include "RtUtilClasses.h"
#include "RtTimerWrapper.h"
#include "RtMessageBlock.h"

class /*RT_API_EXPORT*/ CRtTransportThreadProxy 
	: public IRtTransport
	, public IRtTransportSink
	, public CRtReferenceControlMutilThread
	, public CRtStopFlag
	, public CRtTimerWrapperSink
{
public:
	CRtTransportThreadProxy(
		IRtTransport *aActual, 
		CRtThread *aThreadNetwork,
		CRtThread *aThreadUser,
		CRtConnectionManager::CType aType);

	virtual ~CRtTransportThreadProxy();

	// interface IRtReferenceControl
	virtual DWORD AddReference();
	virtual DWORD ReleaseReference();
	virtual void OnReferenceDestory();

	// interface IRtTransport
	virtual RtResult OpenWithSink(IRtTransportSink *aSink);
	virtual IRtTransportSink* GetSink();
	virtual RtResult SendData(
		CRtMessageBlock& inData,
		BOOL inSendImmediately = TRUE,
		BOOL inDestroyData = FALSE,
		DataPriority inPriority = DP_MEDIUM, 
		BOOL inNeedAck = TRUE);
	virtual RtResult SendData(
		CRtMessageBlock& inData, 
		RtRudpReliability inReliability,
		INT inTTL = -1,
		BOOL inSendImmediately = TRUE,
		BOOL inDestroyData = FALSE,
		DataPriority inPriority = DP_MEDIUM,
		RudpChannel inChannelID = 0); 
	virtual RtResult SetOption(DWORD aCommand, LPVOID aArg);
	virtual RtResult GetOption(DWORD aCommand, LPVOID aArg);
	virtual RtResult Disconnect(RtResult aReason);

	// interface IRtTransportSink
	virtual void OnReceive(
		CRtMessageBlock &aData,
		IRtTransport *aTrptId,
		CRtTransportParameter *aPara = NULL);

	virtual void OnSend(
		IRtTransport *aTrptId,
		CRtTransportParameter *aPara = NULL);

	virtual void OnDisconnect(
		RtResult aReason,
		IRtTransport *aTrptId);

	virtual void OnTimer(CRtTimerWrapper* aId);

private:
	CRtAutoPtr<IRtTransport> m_lowerTransport;
	IRtTransportSink *m_sink;
	CRtThread *m_userThread;
	CRtThread *m_networkThread;
	CRtConnectionManager::CType m_connType;
	CRtTimerWrapper m_deleteTimer;

	struct CBufferItem 
	{
		CBufferItem(
			CRtMessageBlock* inData,
			BOOL inSendImmediately, 
			IRtTransport::DataPriority inPriority, 
			BOOL inNeedAck)
		: m_data(inData)
		, m_sendImmediately(inSendImmediately)
		, m_priority(inPriority)
		, m_needAck(inNeedAck)
		{}
		~CBufferItem()
		{
			if (m_data)
				m_data->DestroyChained();
		}

		CRtMessageBlock* m_data;
		BOOL m_sendImmediately;
		IRtTransport::DataPriority m_priority;
		BOOL m_needAck;
	};
	typedef std::list<CBufferItem> BufferType;

	// for send buffer, we don't need mutex becase.
	// <m_sendBuffer> is modified in the network thread.
	// <m_needOnSend> is modified in the user thread.
	BOOL m_needOnSend;
	BufferType m_sendBuffer;

	friend class CRtEventSendData;
	friend class CRtEventDisconnect;
	friend class CRtEventOnReceive;
	friend class CRtEventOnSend;
	friend class CRtEventOnDisconnect;
};

class CRtEventSendData : public IRtEvent
{
public:
	CRtEventSendData(
		CRtTransportThreadProxy* inThreadProxy,
		CRtMessageBlock* inData, 
		BOOL inSendImmediately,
		IRtTransport::DataPriority inPriority, 
		BOOL inNeedAck);

	virtual ~CRtEventSendData();

	virtual RtResult OnEventFire();

private:
	CRtAutoPtr<CRtTransportThreadProxy> m_threadProxy;
	CRtMessageBlock* m_data;
	BOOL m_sendImmediately;
	IRtTransport::DataPriority m_priority; 
	BOOL m_needAck;
};

class CRtEventDisconnect : public IRtEvent
{
public:
	CRtEventDisconnect(
		CRtTransportThreadProxy *aThreadProxy,
		RtResult aReason);

	virtual ~CRtEventDisconnect();

	virtual RtResult OnEventFire();

private:
	CRtAutoPtr<CRtTransportThreadProxy> m_pOwnerThreadProxy;
	RtResult m_Reason;
};

class CRtEventOnReceive : public IRtEvent
{
public:
	CRtEventOnReceive(
		CRtTransportThreadProxy* inThreadProxy,
		CRtMessageBlock& inData);

	virtual ~CRtEventOnReceive();

	virtual RtResult OnEventFire();

private:
	CRtAutoPtr<CRtTransportThreadProxy> m_threadProxy;
	CRtMessageBlock* m_data;
};

class CRtEventOnSend : public IRtEvent
{
public:
	CRtEventOnSend(CRtTransportThreadProxy* inThreadProxy);

	virtual ~CRtEventOnSend();

	virtual RtResult OnEventFire();

private:
	CRtAutoPtr<CRtTransportThreadProxy> m_threadProxy;
};

class CRtEventOnDisconnect : public IRtEvent
{
public:
	CRtEventOnDisconnect(
		CRtTransportThreadProxy* inThreadProxy,
		RtResult inReason);

	virtual ~CRtEventOnDisconnect();

	virtual RtResult OnEventFire();

private:
	CRtAutoPtr<CRtTransportThreadProxy> m_threadProxy;
	RtResult m_reason;
};

#endif // !RTTRANSPORTTHREADPROXY_H
